#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sge_safe_client_interface.h"
#include "api.h"

const char *g_sge_id = "SGE";
const char *g_trader_id = "plp7001";

#define ENC_MODE_SOFT 1

typedef struct api_ctx_s{
    api_safe_client_t *safe_api;
    api_safe_client_session_t *session_handle;
    api_safe_client_link_t *link;
}api_ctx_t;


#define MSG_SVR_HELLO 1
#define MSG_SVR_SESSION_KEY 2

int get_svr_msg_type(const char *msg, unsigned int con_len){
    // get gtp msg type

    return 0;
}

fld_server_hello_t *gtp2gems_server_hello(const char *msg, unsigned int con_len){
    // convert gtp to fld_server_hello_t

    // mock
    fld_server_hello_t *svr_hello = (fld_server_hello_t*)malloc(sizeof(fld_server_hello_t));

    return svr_hello;
}

int handle_svr_hello(api_safe_client_session_t *ptr, api_safe_client_link_t *link, const char *msg, unsigned int con_len){
    // 1. gtp->gems: server hello
    fld_server_hello_t *svr_hello = gtp2gems_server_hello(msg, con_len);
    if(!svr_hello){
        printf("convert gtp to server hello failed\n");
        return -1;
    }

    // 2. handle server hello
    int ret = sge_safe_client_handle_hello_rsp(ptr, link, svr_hello);
    free(svr_hello);
    if(0 != ret){
        printf("handle server hello failed! error code:%d\n", ret);
        return -2;
    }

    // 3. create authentication
    fld_authentication_info_t *auth_info = (fld_authentication_info_t *)calloc(1, sizeof(fld_authentication_info_t));
    ret = sge_safe_client_create_authentication(ptr, link, auth_info);
    if(0 != ret){
        printf("create authentication info failed! error code:%d\n", ret);
        return -3;
    }

    // 4. convert auth info to gtp

    // 5. send gtp

    free(auth_info);

    return 0;
}

fld_sessionkey_info_t *gtp2gems_sessionkey(const char *msg, unsigned int con_len){
    // convert gtp to fld_sessionkey_info_t

    // mock
    fld_sessionkey_info_t *sessionkey = (fld_sessionkey_info_t*)malloc(sizeof(fld_sessionkey_info_t));

    return sessionkey;
}

int handle_svr_session_key(api_safe_client_session_t *ptr, api_safe_client_link_t *link, const char *msg, unsigned int con_len){
    // 1. gtp to server sessionkey
    fld_sessionkey_info_t *sessionkey = gtp2gems_sessionkey(msg, con_len);
    if(!sessionkey){
        printf("convert gtp2gems sessionkey failed!\n");
        return -1;
    }

    // 2. accept sessionkey
    int ret = sge_safe_client_accept_sessionkey(ptr, link, sessionkey);
    free(sessionkey);
    if(0 != ret){
        printf("handle session key failed! error code:%d\n", ret);
        return -2;
    }

    return 0;
}

static void __recv_msg(const char * msg, int type, unsigned int con_len, void * ctx) {
    api_ctx_t *api_ctx = (api_ctx_t*)ctx;
    if(!api_ctx){
        printf("invalid api ctx!\n");
        return;
    }

    int ret;
    if(GTP_TYPE_STRING == type){
        int msg_type = get_svr_msg_type(msg, con_len);
        switch(msg_type){
            case MSG_SVR_HELLO:
                ret = handle_svr_hello(api_ctx->session_handle, api_ctx->link, msg, con_len);
                if(0 != ret){
                    // disconnect
                }
                break;
            case MSG_SVR_SESSION_KEY:
                ret = handle_svr_session_key(api_ctx->session_handle, api_ctx->link, msg, con_len);
                if(0 != ret){
                    // disconnect
                }
                break;
            default:
                printf("error svr message!\n");
                // disconnect
        }
    }
    else if(GTP_TYPE_ENCRYPT == type){
        unsigned char *buf = (unsigned char*)malloc(con_len);
        unsigned int cap = con_len;
        ret = sge_safe_client_packet_decrypt(api_ctx->session_handle, api_ctx->link, (unsigned char*)msg, con_len, buf, &cap);
        if(0 != ret){
            printf("decrypt msg failed, error code:%d\n", ret);
            // disconnect
        }
        printf("recv msg:%s\n", buf);
        // process msg
        free(buf);
    }
    else{
        printf("invalid msg type!\n");
        // disconnect
    }
}

char *svr_enc_pubkey = "server enc pubkey";
char *svr_sign_pubkey = "server sign pubkey";

session_client_info_t *create_session_client_info(){
    session_client_info_t *session_info = (session_client_info_t*)malloc(sizeof(session_client_info_t));
    if(!session_info)
        return NULL;

    unsigned int len = sizeof(session_info->sge_id_);
    strncpy(session_info->sge_id_, g_sge_id, len);
    session_info->sge_id_[len - 1] = '\0';
    len = sizeof(session_info->trader_id_);
    strncpy(session_info->trader_id_, g_trader_id, len);
    session_info->trader_id_[len - 1] = '\0';
    session_info->enc_mode_ = ENC_MODE_SOFT;
    //session_info->svr_enc_pubkey_ = __set_svr_enc_pubkey();
    memcpy(session_info->svr_enc_pubkey_, svr_enc_pubkey, strlen(svr_enc_pubkey));
    session_info->svr_enc_pubkey_len_ = strlen(svr_enc_pubkey);
    memcpy(session_info->svr_sign_pubkey_, svr_sign_pubkey, strlen(svr_sign_pubkey));
    session_info->svr_sign_pubkey_len_ = strlen(svr_sign_pubkey);

    return session_info;
}

static void __cb_connected(api_connection_state_t * cs, void * ctx) {
    printf("connected to acsvr. ip: %s, port: %d, state: %d\n", cs->ip, cs->port, cs->state);

    api_ctx_t *api_ctx = (api_ctx_t*)ctx;
    if(!api_ctx){
        printf("invalid api ctx!\n");
        // disconnect
        return;
    }

    // 1. create session info
    session_client_info_t *session_info = create_session_client_info();
    if(NULL == session_info){
        printf("alloc session client info failed!\n");
        // disconnect
        return;
    }

    // 2. create session handle
    api_ctx->session_handle = sge_safe_create_client_session(api_ctx->safe_api, session_info);
    free(session_info);
    if(!api_ctx->session_handle){
        printf("create session handle failed\n");
        goto err;
    }

    // 3. create client hello
    fld_client_hello_t *cli_hello = (fld_client_hello_t *)calloc(1, sizeof(fld_client_hello_t));
    int ret = sge_safe_client_create_hello(api_ctx->session_handle, cli_hello);
    if(!ret){
        printf("create client hello failed!\n");
        goto err;
    }

    // 4.convert client hello to gtp

    // 5.send gtp

    free(cli_hello);
    return;

err:
    if(session_info) {
        free(session_info);
        session_info = NULL;
    }
    if(api_ctx->session_handle) {
        sge_safe_free_client_session(api_ctx->session_handle);
        api_ctx->session_handle = NULL;
    }
}

static void __cb_disconnect(api_connection_state_t * cs, void * ctx) {
    printf("disconnect with acsvr. ip: %s, port: %d, state: %d\n", cs->ip, cs->port, cs->state);

    api_ctx_t *api_ctx = (api_ctx_t*)ctx;
    if(!api_ctx){
        printf("invalid api ctx!\n");
        return;
    }

    // free session
    if(api_ctx->session_handle){
        sge_safe_free_client_session(api_ctx->session_handle);
        api_ctx->session_handle = NULL;
    }
}

void send_msg(api_ctx_t *api_ctx){
    char *login_msg = "X03=A100";
    unsigned int msg_len = strlen(login_msg);
    unsigned char *buf = (unsigned char*)malloc(msg_len);
    int ret = sge_safe_client_packet_encrypt(api_ctx->session_handle, api_ctx->link, (unsigned char*)login_msg, msg_len, buf, &msg_len);
    if(0 != ret){
        printf("encrypt msg failed!\n");
    }

    // send msg

    free(buf);
}

int __is_safe_handshake_finished(){
    //check if safe handshake is finished
    return 0;
}

int main(int argc, char *argv[]){
    api_ctx_t api_ctx;

    // 1. create safe api
    api_ctx.safe_api = sge_safe_client_api_create(NULL, ENC_MODE_SOFT);
    if(!api_ctx.safe_api){
        printf("create safe api failed!\n");
        return -1;
    }

    //2.create safe link
    api_ctx.link = sge_safe_client_link_create(api_ctx.safe_api);
    if(!api_ctx.link){
        printf("create safe link failed!\n");
        goto err;
    }

    // 3. create api
    api_cb_t api_cb = {__recv_msg, __cb_connected, __cb_disconnect};
    api_t *api = api_init("127.0.0.1", 6666, &api_cb, &api_ctx);
    if(!api){
        printf("init api failed!\n");
        goto err;
    }

    // 4. wait server session key
    while(__is_safe_handshake_finished() == 0) {
        ;
    }

    // 5. login, order apply, ..., logout
    send_msg(&api_ctx);

    api_wait(api);

err:
    if(api) {
        api_free(api);
    }

    if(api_ctx.link) {
        sge_safe_client_link_destroy(api_ctx.link);
        api_ctx.link = NULL;
    }

    if(api_ctx.safe_api) {
        sge_safe_client_api_destroy(api_ctx.safe_api);
        api_ctx.safe_api = NULL;
    }

    return 0;
}
 

